#######这一模块改自别人代码。
#######主要计算了银行竞品，联系密度，计数类等特征。
#######主要通过字典列表等数据结构来实现

from copy import deepcopy
import os
import re

def get_root_dir(path):
    path_list=path.split(os.path.sep)
    index=path_list.index("featurelib")
    return os.path.sep.join(path_list[:index+1])
    
class CallUnBase0V1Module2():
    def main(self,data):
        self.gen_context(data)
        res_map=self.call_feature()
        return res_map
    def __init__(self):

        self.day_sections = [(30, 'm1'), (60, 'm2'), (90, 'm3'), (10000, 'all')]
        self.year_sections = [(365, 'y1'), (730, 'y2'), (1825, 'y5'), (3650, 'y10'), (7300, 'y20')]
        self.phone_types = ['all', 'compete', 'bank', 'common', 'other']
        self.call_types = ['all'] + ['c%d' % x for x in range(1, 8)]
        self.du_types = ['all', 'd0', 'd1', 'd2']
        cur_path=(os.path.abspath('.'))
        root_path=get_root_dir(cur_path)
        path=os.path.join(root_path, 'feature_conf','call','un','call_un_base0_v1', 'call_un_base0_v1_module2.featlist')
        self.res_map={k.strip().split('|')[0].strip():'None' for k in open(path,encoding='utf-8')}
    def gen_context(self, data=None):
        self.compete_keyword=data['country_info']['compete_kw_words']
        self.bank_keyword=data['country_info']['bank_kw_words']
        self.special_phone_dict = data['country_info']['phone_dict']
        clean_call_list = []
        for call in (data['call_list']):
            call['call_type'] = 'c%s' % call['type'] 
            duration = float(call['duration'])
            call['duration_type'] = 'd%s' % ('0' if duration <= 0 else '1' if duration < 60 else '2')
            phone=call['phone']
            is_compete_by_kw = self.compete_check_by_keywords(call['name'])
            is_compete_by_mobile = self.check_by_phone(phone, 'compete')
            call['is_compete_phone'] = True if is_compete_by_kw or is_compete_by_mobile else False
            is_bank_by_kw = self.bank_check_by_keywords(call['name'])
            is_bank_by_mobile = self.check_by_phone(phone, 'bank')
            call['is_bank_phone'] = True if is_bank_by_kw or is_bank_by_mobile else False
            call['is_common_phone'] = True if self.check_by_phone(phone, 'common') else False
            call['phone_type'] = 'common' if call['is_common_phone'] else 'compete' if call['is_compete_phone'] else 'bank' if call['is_bank_phone'] else 'other'
            clean_call_list.append(call)
        data['call_list'] = deepcopy(clean_call_list)
        self.data=deepcopy(data)

    def init_feature_dic(self):
        feature_dic = deepcopy(self.res_map)
        for ds in self.day_sections:
            for pt in self.phone_types:
                for ct in self.call_types:
                    for dt in self.du_types:
                        feature_dic['call_cnt_%s_%s_%s_%s' % (ds[1], pt, ct, dt)] = 0.0
                        feature_dic['call_duration_%s_%s_%s_%s' % (ds[1], pt, ct, dt)] = 0.0
                    if ct != 'all':
                        feature_dic['call_ct_cnt_%s_%s_single_phone_max' % (ds[1], ct)] = 0
            feature_dic['call_phone_num_%s' % ds[1]] = 0
            feature_dic['call_name_num_%s' % ds[1]] = 0
            feature_dic['call_cnt_%s_per_day_max' % ds[1]] = 0
        for ys in self.year_sections:
            feature_dic['call_cnt_%s_ago' % ys[1]] = 0
        return feature_dic

    def call_cnt_ratio_feature(self, feature_dic):
        for ds in self.day_sections:
            for ct in self.call_types:
                if ct == 'all':
                    continue
                ct_feature_name = 'call_cnt_%s_all_%s_all' % (ds[1], ct)
                all_feature_name = 'call_cnt_%s_all_all_all' % ds[1]
                ct_feature_value = feature_dic[ct_feature_name]
                all_feature_value = feature_dic[all_feature_name]
                feature_name = 'call_ct_cnt_ratio_%s_%s' % (ds[1], ct)
                feature_value = 0.0 if all_feature_value == 0 else float(ct_feature_value) / all_feature_value
                feature_dic[feature_name] = feature_value
            for pt in self.phone_types:
                if pt in ('all', 'common'):
                    continue
                pt_feature_name = 'call_cnt_%s_%s_all_all' % (ds[1], pt)
                all_feature_name = 'call_cnt_%s_all_all_all' % ds[1]
                pt_feature_value = feature_dic[pt_feature_name]
                all_feature_value = feature_dic[all_feature_name]
                feature_name = 'call_pt_cnt_ratio_%s_%s' % (ds[1], pt)
                feature_value = 0.0 if all_feature_value == 0 else float(pt_feature_value) / all_feature_value
                feature_dic[feature_name] = feature_value
        for ys in self.year_sections:
            ys_feature_name = 'call_cnt_%s_ago' % ys[1]
            all_feature_name = 'call_cnt_all_all_all_all'
            ys_feature_value = feature_dic[ys_feature_name]
            all_feature_value = feature_dic[all_feature_name]
            feature_name = 'call_cnt_ratio_%s_ago' % ys[1]
            feature_value = 0.0 if all_feature_value == 0 else float(ys_feature_value) / all_feature_value
            feature_dic[feature_name] = feature_value

    def call_cnt_max_phone_feature(self, feature_dic, phone_ct_dic):
        for ds in phone_ct_dic:
            for i in range(7):
                max_cnt = 0
                for phone in phone_ct_dic[ds]:
                    max_cnt = phone_ct_dic[ds][phone][i] if phone_ct_dic[ds][phone][i] > max_cnt else max_cnt
                feature_name = 'call_ct_cnt_%s_c%d_single_phone_max' % (ds, i + 1)
                feature_dic[feature_name] = max_cnt

    def call_phone_nums_feature(self, feature_dic, phone_dic, name_dic):
        for ds in phone_dic:
            phone_num = len(phone_dic[ds])
            feature_name = 'call_phone_num_%s' % ds
            feature_dic[feature_name] = phone_num
            name_num = len(name_dic[ds])
            feature_name = 'call_name_num_%s' % ds
            feature_dic[feature_name] = name_num

    def call_cnt_max_day_feature(self, feature_dic, per_day_cnt_dic):
        for ds in per_day_cnt_dic:
            max_cnt = 0
            for diff_days in per_day_cnt_dic[ds]:
                max_cnt = per_day_cnt_dic[ds][diff_days] if per_day_cnt_dic[ds][diff_days] > max_cnt else max_cnt
            feature_name = 'call_cnt_%s_per_day_max' % ds
            feature_dic[feature_name] = max_cnt

    def calculate_density(self, section, data_list):
        filter_data = [x for x in data_list if x <= section]
        filter_data.append(section)
        result = pow(filter_data[0], 2)
        for i in range(1, len(filter_data)):
            result += pow((filter_data[i] - filter_data[i - 1]), 2)
        density = pow(result, 0.5)
        return density

    def call_feature(self):
        feature_dic = self.init_feature_dic()
        phone_ct_dic = {}
        phone_dic = {}
        name_dic = {}
        per_day_cnt_dic = {}
        diff_day_set = set()
        for call in self.data['call_list']:
            current_phone_types = ['all', call['phone_type']]
            current_call_types = ['all', call['call_type']]
            current_du_types = ['all', call['duration_type']]
            phone = call['phone']
            name = call['name']
            diff_days = call['diff_days']
            diff_day_set.add(diff_days)
            for ds in self.day_sections:
                if diff_days > ds[0]:
                    continue
                if ds[1] not in phone_ct_dic:
                    phone_ct_dic[ds[1]] = {}
                    phone_dic[ds[1]] = set()
                    name_dic[ds[1]] = set()
                    per_day_cnt_dic[ds[1]] = {}
                phone_dic[ds[1]].add(phone)
                name_dic[ds[1]].add(name)
                if diff_days not in per_day_cnt_dic[ds[1]]:
                    per_day_cnt_dic[ds[1]][diff_days] = 0
                per_day_cnt_dic[ds[1]][diff_days] += 1
                if phone not in phone_ct_dic[ds[1]]:
                    phone_ct_dic[ds[1]][phone] = [0] * 7
                phone_ct_dic[ds[1]][phone][int(call['type']) - 1] += 1
                for phone_type in current_phone_types:
                    for call_type in current_call_types:
                        for du_type in current_du_types:
                            cnt_feature_name = 'call_cnt_%s_%s_%s_%s' % (ds[1], phone_type, call_type, du_type)
                            feature_dic[cnt_feature_name] += 1

                            duration_feature_name = 'call_duration_%s_%s_%s_%s' % (ds[1], phone_type, call_type, du_type)
                            feature_dic[duration_feature_name] += float(call['duration'])
            for ys in self.year_sections:
                if diff_days <= ys[0]:
                    continue
                cnt_feature_name = 'call_cnt_%s_ago' % ys[1]
                feature_dic[cnt_feature_name] += 1
        diff_day_list = list(diff_day_set)
        diff_day_list.sort()
        min_diff_day = max_diff_day = 0
        if len(diff_day_list) > 0:
            min_diff_day = diff_day_list[0]
            max_diff_day = diff_day_list[-1]
        feature_dic['day_diff_first_call_time'] = max_diff_day
        feature_dic['day_diff_last_call_time'] = min_diff_day
        density_sections = [(30, 'm1'), (60, 'm2'), (90, 'm3'), (120, 'm4')]
        for density_section in density_sections:
            density = self.calculate_density(density_section[0], diff_day_list)
            feature_name = 'call_density_%s' % density_section[1]
            feature_dic[feature_name] = density
        self.call_cnt_ratio_feature(feature_dic)
        self.call_cnt_max_phone_feature(feature_dic, phone_ct_dic)
        self.call_phone_nums_feature(feature_dic, phone_dic, name_dic)
        self.call_cnt_max_day_feature(feature_dic, per_day_cnt_dic)
        return  feature_dic


    def family_name_check(self, cn, name):
        family_keywords_set = self.country_info['family_set']
        name = name.lower()
        if name in family_keywords_set:
            return True
        return False

    def compete_check_by_keywords(self, name):
        name = name.lower()
        for kw in self.compete_keyword:
            if kw in name:
                return True
        return False

    def bank_check_by_keywords(self, name):
        name_split = name.lower().split(' ')
        for ns in name_split:
            if ns in self.bank_keyword:
                return True
        return False

    def check_by_phone(self, phone, phone_type):
        if phone_type not in self.special_phone_dict:
            return False
        if phone in self.special_phone_dict[phone_type]:
            return True
        return False


    def _load_country_keywords(self):
        language_dict = {'51': 'spn_cn', '56': 'spn_cn', '34': 'spn_cn'}
        country_keywords_dict = {
            'spn_cn': {
                'family': [
                    'mama', 'papa', 'mamá', 'papá', 'mami', 'suegra', 'mamita', 'suegro', 'tata',
                    'papi', 'papito', 'madre', 'hijo', 'abuela', 'hija', 'primo', 'prima', 'suegrita',
                    'darling', 'marito', 'hermanita', 'casero', 'esposa', 'esposo', 'cariño', 'casa',
                    'ma', 'padre', 'pa', 'amor', 'amorcito', 'amore', 'hermano'],
                'compete': ['crédito', 'credito', 'préstamos', 'presta', 'prestó'],
                'bank': ['banco', 'bci', 'bank', 'banca']
            },
            'eng_cn': {
                'family': ['brother'],
                'compete': [],
                'bank': []
            },
            '52': {
                'family': [
                    'mama', 'mamá', 'mami', 'ma', 'madre', 'mom', 'casa', 'mamó', 'mamita',
                    'papa', 'papá', 'pa', 'daddy', 'dad', 'dady', 'papi', 'papito', 'tata', 'padre',
                    'suegra', 'suegro', 'suegroo', 'suegrita', 'consuegra', 'cuñado', 'casero',
                    'hijo', 'hija', 'fillo', 'hijos', 'son',
                    'primo', 'prima', 'hermanita', 'hermano', 'hermanito', 'hermana', 'sister',
                    'abuela', 'bizcabuela', 'abuelo', 'abuelos',
                    'esposa', 'esposo', 'marito',
                    'darling', 'cariño', 'amor', 'amorcito', 'amore'],
                'compete': ['préstamos', 'presta', 'prestó', 'loan', 'prstamo', 'hipotecario',
                            'prestemos', 'presatamos', 'prstmo', 'prstamo',
                            'crédit', 'credit', 'credifranco', 'credisoluciones', 'kredit',
                            'cash', 'efectivo', 'dinero', 'money'],
                'bank': ['bienestarbanco', 'banamex', 'banco', 'hsbc', 'credibank', 'bancomex',
                         'citi', 'bancaria', 'bancomer', 'bank', 'scotiabank', 'citibanamex',
                         'bis', 'banca', 'ebanking', 'bbva', 'orilla', 'bancomext', 'bancarios',
                         'bci', 'banc', 'bancopel', 'bancoppel', 'bankaya', 'banxico']
            }
        }
        for cn in country_keywords_dict:
            country_keywords_dict[cn]['family_set'] = set(country_keywords_dict[cn]['family'])
            country_keywords_dict[cn]['bank_set'] = set(country_keywords_dict[cn]['bank'])
        return language_dict, country_keywords_dict
